#pragma once


#include"Graph.h"
#include"Generators.h"
#include<set>
#include<vector>
#include<stdexcept>
#include<algorithm>
#include<crtdbg.h>

template<class TemplateGraph>
void graphesAdjacentCheck(const TemplateGraph& G, const std::vector<Edge>& edgesList,
	const std::string& classGraph){
	int vertexNum = G.getVertexNum();
	std::set<Edge> edgesSet;
	for (auto currentEdge : edgesList){
		edgesSet.insert(currentEdge);
	}
	std::set<Edge> edgesFromAdjacentLists;
	for (int currentVertex = 0; currentVertex < vertexNum; ++currentVertex){
		std::vector<int> adjacentList = G.getAdjacentList(currentVertex);
		for (auto toVertex : adjacentList){
			Edge currentEdge = {currentVertex, toVertex};
			if (edgesSet.count(currentEdge) == 0){
				throw std::logic_error("Extra edges in adjacent list of " +  classGraph + " Graph");
			}
			edgesFromAdjacentLists.insert(currentEdge);
		}
	}
	for (auto currentEdge : edgesSet){
		if (edgesSet.count(currentEdge) == 0){
			throw std::logic_error("There isn't enough edges in " + classGraph + "Graph");
		}
	}
}


void listGraphesUnitCheck();
void matrixGraphesUnitCheck();
#ifdef _DEBUG
void detectedMemoryLeaks(const std::string& testType);

template<class templateGraph>
void memoryLeaksCheck(int vertexNum, const std::vector<Edge>& edgesList, const std::string& typeGraph){
	_CrtMemState beforeGraph;
	_CrtMemCheckpoint(&beforeGraph);
	{
		_CrtMemState memoryStateBeforeCreating;
		_CrtMemCheckpoint(&memoryStateBeforeCreating);
		templateGraph G(vertexNum, edgesList);

	}
	_CrtMemState afterGraph;
	_CrtMemCheckpoint(&afterGraph);
	_CrtMemState differenceMemory;
	if (_CrtMemDifference(&differenceMemory, &beforeGraph, &afterGraph)){
		detectedMemoryLeaks(typeGraph + " graph");
	}
}



size_t compactGraphMemoryCount(int vertexNum, const std::vector<Edge> & edgesList);
void graphChooseStressCheck();

void memoryLeaksListUnitTests();
void memoryLeaksMatrixUnitTests();
void memoryTestGraphes(const std::string& typeGraph, int vertexNum, const std::vector<Edge>& edgesList);
void memoryCheckEmptyGraph();
void memoryCheckFullGraph();
void memoryCheckRandomGraph();
void memoryCheckAcyclicGraph();
void memoryCheckFunctionalGraphs();


#endif

void unitTestsAdjacent();
#ifndef _DEBUG
void timeCheckEmptyGraphs();
void timeCheckFullGraph();
void timeCheckRandomGraph();

void checkTopologySort(const Graph& G, const std::vector<int>& answerOrder){
	int vertexNum = G.getVertexNum();
	std::set<Edge> badEdgesSet;					  
	for (int fromVertex = 0; fromVertex < vertexNum; ++fromVertex){
		std::vector<int> adjacentList = G.getAdjacentList(fromVertex);
		for (auto toVertex : adjacentList){
			badEdgesSet.insert({ toVertex, fromVertex });
		}
	}
	for (size_t mayFromVertex = 0; mayFromVertex < answerOrder.size(); ++mayFromVertex){
		for (size_t mayToVertex = mayFromVertex + 1; mayToVertex < answerOrder.size(); ++mayToVertex){
			if (badEdgesSet.count({ answerOrder[mayFromVertex], answerOrder[mayToVertex] }) > 0){
				throw std::logic_error("Wrong topology sort order");
			}
		}
	}
}

void timeAndTopologyCheckAcyclicGraph();



void timeCheckFunctionalGraphs();

#endif //_DEBUG


void unitTestsTopology();

void BFSUnitTests();

void DFSUnitTests();

void DFSInsideCheck();


